//
//  XDXLocationManager.m
//  location
//
//  Created by Dongxiang Xu on 2024/6/6.
//

#import "XDXLocationManager.h"
#import "HomeViewController.h"
#import "SOMotionDetector.h"
#import "FMDatabase.h"
#import "FMDatabaseQueue.h"
#import "WGS84TOGCJ02.h"
#import "TrackTool.h"
#import "GeofenceInfo.h"
#import "XDXGeofenceCoordinator.h"

#define HIGH_ACCURACY_DISTANCE 1.0 // 驾车模式距离阈值
#define WALK_ACCURACY_DISTANCE 1.0 // 步行模式距离阈值
#define LOW_ACCURACY_DISTANCE 100.0 // 静止模式距离阈值

// 静止速度阈值上限
#define STATIC_SPEED_THRESHOLD 3
// 步行速度阈值 （>阈值为驾车）
#define WALK_SPEED_THRESHOLD 10



static XDXLocationManager *shareInstance = nil;

@interface XDXLocationManager ()<CLLocationManagerDelegate>

// 传感器获取到的临时activity
@property (nonatomic,strong) NSString *tempActivity;
@property (nonatomic,strong) NSTimer *staticTimer;

// 电量相关
@property (nonatomic, assign) NSInteger batteryTime;
@property (nonatomic, assign) BOOL batteryUp; // 电量大于了10%

// 驾驶报告相关
@property (nonatomic, strong) NSTimer *drivingTimer;
@property (nonatomic, strong) NSTimer *drivingLoopTimer; // 每300s检测一次有没有已经完成的驾驶，发出推送
@property (nonatomic, strong) NSMutableArray *driveLog;
@property (nonatomic, strong) NSMutableArray *regionLog;

// 上传记录相关
@property (nonatomic, assign) NSInteger uploadTime;
@property (nonatomic, assign) BOOL unLock;
@property (nonatomic, strong) NSMutableArray *pointBatch;

// MARK: - 围栏相关属性
@property (nonatomic, strong) NSMutableArray<GeofenceInfo *> *geofenceList; // 围栏列表
@property (nonatomic, strong) XDXGeofenceCoordinator *geofenceCoordinator; // 围栏融合协调器
@property (nonatomic, assign) NSInteger lastRegionReconfigTime; // 最近一次 Region 旋转时间戳


@end

@implementation XDXLocationManager

+ (instancetype)shareInstance
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        if (shareInstance == nil) {
            shareInstance = [[self alloc] init];
        }
    });
    return shareInstance;
}

- (void)initialize
{
    if (self.locationManager==nil) {
        self.locationManager = [[CLLocationManager alloc] init];
        self.locationManager.delegate = self;
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        self.locationManager.distanceFilter = kCLDistanceFilterNone;
        [self.locationManager setAllowsBackgroundLocationUpdates:YES];
        [self.locationManager setPausesLocationUpdatesAutomatically:NO];
        [self.locationManager requestWhenInUseAuthorization];
    }
}

- (void)loadData
{
    if (!self.driveLog) {
        // 注册解锁通知
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleScreenUnlock:) name:UIApplicationProtectedDataDidBecomeAvailable object:nil];
        
        {
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
            NSString *documentsDirectory = paths.firstObject;
            NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"driveLog.plist"];
            NSFileManager *fileManager = [[NSFileManager  alloc] init];
            if(![fileManager fileExistsAtPath:plistPath]){
                [fileManager createFileAtPath:plistPath contents:nil attributes:nil];
            }
          
            self.driveLog = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
            if (!self.driveLog) {
                self.driveLog = [NSMutableArray array];
            }
        }
        {
            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
            NSString *documentsDirectory = paths.firstObject;
            NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"regionLog.plist"];
            NSFileManager *fileManager = [[NSFileManager  alloc] init];
            if(![fileManager fileExistsAtPath:plistPath]){
                [fileManager createFileAtPath:plistPath contents:nil attributes:nil];
            }
          
            self.regionLog = [[NSMutableArray alloc] initWithContentsOfFile:plistPath];
            if (!self.regionLog) {
                self.regionLog = [NSMutableArray array];
            }
        }
        
        self.tempActivity = @"静止";
        [SOMotionDetector sharedInstance].motionTypeChangedBlock = ^(SOMotionType motionType) {
            if (motionType==MotionTypeNotMoving) {
                self.tempActivity = @"静止";
            } else if (motionType==MotionTypeWalking) {
                self.tempActivity = @"步行";
            } else if (motionType==MotionTypeRunning) {
                self.tempActivity = @"步行";
            } else if (motionType==MotionTypeAutomotive) {
                self.tempActivity = @"驾车";
            }
        };
        [[SOMotionDetector sharedInstance] startDetection];
        
        self.lastlog = @"";
        self.activityString = @"静止";
        self.batteryUp = YES;
        self.pointBatch = [NSMutableArray array];
        
        // 初始化围栏相关属性
        self.geofenceList = [NSMutableArray array];

       
        self.geofenceCoordinator = [[XDXGeofenceCoordinator alloc] init];
        __weak typeof(self) weakSelf = self;
        self.geofenceCoordinator.onFenceEvent = ^(GeofenceInfo *fence, BOOL didEnter) {
            __strong typeof(weakSelf) strongSelf = weakSelf;
            if (!strongSelf) return;
            if (didEnter) {
                [strongSelf triggerGeofenceEntry:fence];
            } else {
                [strongSelf triggerGeofenceExit:fence];
            }
        };
        self.lastRegionReconfigTime = 0;
        
        self.drivingLoopTimer = [NSTimer scheduledTimerWithTimeInterval:300 repeats:YES block:^(NSTimer * _Nonnull timer) {
            [[HomeViewController new] getMemberInfoWithUserId:[XDXShareInstance shareInstance].userId Date:[[XDXTimeTool currentDate] substringToIndex:10] Success:^(NSArray *data) {
                [self readMoreDataWithData:data IsLoopCheck:YES];
            } Error:^(NSDictionary *data) {

            }];
        }];
        [[NSRunLoop currentRunLoop] addTimer:self.drivingLoopTimer forMode:NSDefaultRunLoopMode];
        
        // 注册电池电量变化的通知
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(batteryLevelDidChange:)
                                                     name:UIDeviceBatteryLevelDidChangeNotification
                                                   object:nil];
        [[UIDevice currentDevice] setBatteryMonitoringEnabled:YES];
    }    
}


- (void)locationManagerDidChangeAuthorization:(CLLocationManager *)manager
{
    if ([[XDXLocationManager shareInstance].locationManager authorizationStatus] == kCLAuthorizationStatusNotDetermined) {
        [self.locationManager requestWhenInUseAuthorization];
    }else if ([[XDXLocationManager shareInstance].locationManager authorizationStatus] == kCLAuthorizationStatusAuthorizedWhenInUse){
        [[NSNotificationCenter defaultCenter] postNotificationName:Noti_Launch_Location object:nil userInfo:@{}];
        [self.locationManager requestAlwaysAuthorization];
    }else{
        CLLocationCoordinate2D loc = [WGS84TOGCJ02 transformFromWGSToGCJ:[[XDXLocationManager shareInstance].lastLocation coordinate]];
        NSDictionary *dict = @{@"type":@"location_update",@"location":@{@"latitude":[NSString stringWithFormat:@"%f",loc.latitude],@"longitude":[NSString stringWithFormat:@"%f",loc.longitude],@"activity":self.activityString,@"speed":[NSString stringWithFormat:@"%d",self.lastLocation.speed<0?0:(int)(self.lastLocation.speed*3.6)],@"nickName":[XDXShareInstance shareInstance].nickName,@"lastLog":self.lastlog,@"battery":[NSString stringWithFormat:@"%.0f",[UIDevice currentDevice].batteryLevel*100],@"isCharge":([UIDevice currentDevice].batteryState==UIDeviceBatteryStateCharging)?@"1":@"0",@"isLocationAuth":([self.locationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedAlways?@(1):@(0))}};
        [[XDXSocket shareInstance] sendMessage:dict];
        if (self.XDXLocationManagerLocationBlock) {
            self.XDXLocationManagerLocationBlock(dict);
        }
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading
{
    if (self.XDXLocationManagerHeadBlock) {
        self.XDXLocationManagerHeadBlock(newHeading.trueHeading);
    }
    
    if (self.UIApplicationLaunchOptionsLocationKey) {
        [self.locationManager stopUpdatingHeading];
    }
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations
{
    if (locations.count>0) {
        CLLocation *newLocation = [locations lastObject];
        
        // 位置有效性校验
        if (newLocation.horizontalAccuracy < 0) return;
        
        // 时间间隔判断
        NSTimeInterval interval = [newLocation.timestamp timeIntervalSinceDate:self.fliterTime];
        if (interval < 2) return;
        
        // 距离过滤
        if (self.lastLocation) {
            CLLocationDistance distance = [newLocation distanceFromLocation:self.lastLocation];
            if (distance < newLocation.horizontalAccuracy) return;
        }
        
        // 后台任务处理
        __block UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication]
                                                     beginBackgroundTaskWithExpirationHandler:^{
            [[UIApplication sharedApplication] endBackgroundTask:bgTask];
            bgTask = UIBackgroundTaskInvalid;
        }];
        // 保存有效位置
        self.lastLocation = newLocation;
        // 投喂 GPS 位置到融合器
        if (self.geofenceCoordinator) {
            [self.geofenceCoordinator ingestLocation:newLocation];
            // 按时间窗旋转系统 Region（每 120 秒一次）
            NSInteger nowTs = [[XDXTimeTool getNowTimeTimestamp] integerValue];
            if (nowTs - self.lastRegionReconfigTime >= 120 && self.geofenceList.count>0) {
                self.lastRegionReconfigTime = nowTs;
                [self.geofenceCoordinator reconfigureMonitoredRegionsWithLocationManager:self.locationManager currentLocation:newLocation maxRegionCount:20];
            }
        }
        
        [[UIApplication sharedApplication] endBackgroundTask:bgTask];
       
        self.fliterTime = [NSDate date];                  
    }
}

- (void)locationManager:(CLLocationManager *)manager didVisit:(CLVisit *)visit
{
    // 交由融合协调器处理（内部包含去抖与合并判定）
    if (self.geofenceCoordinator) {
        [self.geofenceCoordinator ingestVisit:visit];
    }
    BOOL isDepartureEvent = ![[visit departureDate] isEqualToDate:[NSDate distantFuture]];
    if (!isDepartureEvent) {
        [self.staticTimer invalidate];
        self.staticTimer = nil;
        [self setTheActivityString:@"静止"];
        
        [[HomeViewController new] getMemberInfoWithUserId:[XDXShareInstance shareInstance].userId Date:[[XDXTimeTool currentDate] substringToIndex:10] Success:^(NSArray *data) {
            [self readMoreDataWithData:data IsLoopCheck:NO];
        } Error:^(NSDictionary *data) {

        }];
    }
}

- (void)getUserLocations
{
    NSMutableDictionary *param = [NSMutableDictionary dictionary];
    CryptoHTTPKit *manager = [[CryptoHTTPKit alloc] init];
    [manager encryptedPOST:@"/system/group/monitoredusergeofences"
    parameters:param
    success:^(NSDictionary *responseObject) {
        if ([responseObject[@"code"] integerValue]==200) {
            // 清空现有围栏数据
            [self.geofenceList removeAllObjects];
            
            NSLog(@"[Geofence] 开始解析围栏数据，共 %ld 个围栏", (unsigned long)[responseObject[@"data"] count]);
            
            for (NSDictionary *location in responseObject[@"data"]) {
                // 创建围栏信息对象
                GeofenceInfo *geofenceInfo = [[GeofenceInfo alloc] initWithDictionary:location];
                if (geofenceInfo) {
                    [self.geofenceList addObject:geofenceInfo];
                }
            }

            NSLog(@"[Geofence] 围栏数据解析完成，共 %ld 个围栏", (unsigned long)self.geofenceList.count);
            // 更新融合协调器的围栏数据，并配置系统 Region 监控
            if (self.geofenceCoordinator) {
                [self.geofenceCoordinator updateGeofences:self.geofenceList currentLocation:self.lastLocation];
                if (self.lastLocation) {
                    [self.geofenceCoordinator reconfigureMonitoredRegionsWithLocationManager:self.locationManager currentLocation:self.lastLocation maxRegionCount:20];
                    self.lastRegionReconfigTime = [[XDXTimeTool getNowTimeTimestamp] integerValue];
                }
            }
        }
    }
    failure:^(NSError *aError) {
        
    }];
}

- (void)setTheActivityString:(NSString *)activityString 
{
    if (!activityString) {
        self.activityString = @"静止";
    }else{
        self.activityString = [NSString stringWithString:activityString];
    }
    if ([self.activityString isEqualToString:@"静止"]) {
        self.staticTimer = [NSTimer scheduledTimerWithTimeInterval:120 repeats:NO block:^(NSTimer * _Nonnull timer) {
            self.locationManager.distanceFilter = LOW_ACCURACY_DISTANCE;
            [self.locationManager setPausesLocationUpdatesAutomatically:YES];
            self.locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters;
            self.locationManager.activityType = CLActivityTypeOther;
        }];
    }else if ([self.activityString isEqualToString:@"步行"] || [self.activityString isEqualToString:@"骑行"]){
        [self.staticTimer invalidate];
        self.staticTimer = nil;
        self.locationManager.distanceFilter = kCLDistanceFilterNone;
        [self.locationManager setPausesLocationUpdatesAutomatically:NO];
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        self.locationManager.activityType = CLActivityTypeFitness;
    }else if ([self.activityString isEqualToString:@"驾车"] ){
        [self.staticTimer invalidate];
        self.staticTimer = nil;
        self.locationManager.distanceFilter = kCLDistanceFilterNone;
        [self.locationManager setPausesLocationUpdatesAutomatically:NO];
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    }else if ([self.activityString isEqualToString:@"sos"] ){
        [self.staticTimer invalidate];
        self.staticTimer = nil;
        self.locationManager.distanceFilter = kCLDistanceFilterNone;
        [self.locationManager setPausesLocationUpdatesAutomatically:NO];
        self.locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
        self.locationManager.activityType = CLActivityTypeAutomotiveNavigation;
    }
}

- (void)setLastLocation:(CLLocation *)lastLocation
{
    _lastLocation = lastLocation;
    NSInteger maxSpeed = 150;
    if ([self.activityString isEqualToString:@"静止"]) {
        maxSpeed = 5;
    }else if ([self.activityString isEqualToString:@"步行"]){
        maxSpeed = 20;
    }else if ([self.activityString isEqualToString:@"骑行"]){
        maxSpeed = 40;
    }else if ([self.activityString isEqualToString:@"驾车"]){
        maxSpeed = 150;
    }
   
    CGFloat tempSpeed = 0.0;
    if (lastLocation.speed<0) {
        tempSpeed = 0.0;
    }
    if ([self.tempActivity isEqualToString:@"驾车"] || tempSpeed>=WALK_SPEED_THRESHOLD){
        [self setTheActivityString:@"驾车"];
    }else if ([self.tempActivity isEqualToString:@"步行"] || (tempSpeed>=STATIC_SPEED_THRESHOLD && tempSpeed<WALK_SPEED_THRESHOLD)) {
        [self setTheActivityString:@"步行"];
    }else if (tempSpeed<STATIC_SPEED_THRESHOLD && [self.tempActivity isEqualToString:@"静止"]){
        [self setTheActivityString:@"静止"];
    }
    
    if (lastLocation.speed<maxSpeed && _lastLocation) {
        [self getStreetNameWithLocation:_lastLocation];
    }
}

// 获取到反地理编码后发送socket出去
- (void)getStreetNameWithLocation:(CLLocation *)aLocation
{
    CLLocationCoordinate2D loc = [WGS84TOGCJ02 transformFromWGSToGCJ:[aLocation coordinate]];
    CLLocation *location = [[CLLocation alloc] initWithCoordinate:loc altitude:aLocation.altitude horizontalAccuracy:aLocation.horizontalAccuracy verticalAccuracy:aLocation.verticalAccuracy course:aLocation.course speed:aLocation.speed timestamp:[NSDate date]];
    // 将数据加入批处理
    [self addLocationToBatch:location];
    
    // 实时的定位发送socket
    CLGeocoder *geocoder = [[CLGeocoder alloc] init];
    [geocoder reverseGeocodeLocation:aLocation completionHandler:^(NSArray *placemarks, NSError *error) {
        if (error) {
            NSMutableDictionary *param = [NSMutableDictionary dictionary];
            [param setValue:[NSString stringWithFormat:@"%f",location.coordinate.latitude] forKey:@"lat"];
            [param setValue:[NSString stringWithFormat:@"%f",location.coordinate.longitude] forKey:@"lon"];
            [param setValue:@"1" forKey:@"status"];
            CryptoHTTPKit *manager = [[CryptoHTTPKit alloc] init];
            [manager encryptedPOST:@"/apps/data/reversecode"
            parameters:param
            success:^(NSDictionary *responseObject) {
                if ([responseObject[@"code"] integerValue]==200) {
                    NSString *lastLog = @"";
                    self.lastlog = [NSString stringWithFormat:@"%@",responseObject[@"data"][@"street"]];
                    self.lastlog = lastLog;
                    
                    if (self.lastlog.length>0) {
                        NSDictionary *dict = @{@"type":@"location_update",@"location":@{@"latitude":[NSString stringWithFormat:@"%f",location.coordinate.latitude],@"longitude":[NSString stringWithFormat:@"%f",location.coordinate.longitude],@"activity":self.activityString,@"speed":[NSString stringWithFormat:@"%d",location.speed<0?0:(int)(location.speed*3.6)],@"nickName":[XDXShareInstance shareInstance].nickName,@"lastLog":lastLog,@"battery":[NSString stringWithFormat:@"%.0f",[UIDevice currentDevice].batteryLevel*100],@"isCharge":([UIDevice currentDevice].batteryState==UIDeviceBatteryStateCharging)?@"1":@"0",@"isLocationAuth":([self.locationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedAlways?@(1):@(0))}};
                        [[XDXSocket shareInstance] sendMessage:dict];
                        if (self.XDXLocationManagerLocationBlock) {
                            self.XDXLocationManagerLocationBlock(dict);
                        }
                    }
                }
            }
            failure:^(NSError *aError) {
                
            }];
        } else {
            if (placemarks.count > 0) {
                CLPlacemark *placemark = [placemarks objectAtIndex:0];
                self.lastlog = [NSString stringWithFormat:@"%@",placemark.name];
                if (self.lastlog.length>0) {
                    NSDictionary *dict = @{@"type":@"location_update",@"location":@{@"latitude":[NSString stringWithFormat:@"%f",location.coordinate.latitude],@"longitude":[NSString stringWithFormat:@"%f",location.coordinate.longitude],@"activity":self.activityString,@"speed":[NSString stringWithFormat:@"%d",location.speed<0?0:(int)(location.speed*3.6)],@"nickName":[XDXShareInstance shareInstance].nickName,@"lastLog":self.lastlog,@"battery":[NSString stringWithFormat:@"%.0f",[UIDevice currentDevice].batteryLevel*100],@"isCharge":([UIDevice currentDevice].batteryState==UIDeviceBatteryStateCharging)?@"1":@"0",@"isLocationAuth":([self.locationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedAlways?@(1):@(0))}};
                    [[XDXSocket shareInstance] sendMessage:dict];
                    if (self.XDXLocationManagerLocationBlock) {
                        self.XDXLocationManagerLocationBlock(dict);
                    }
                }
            } else {

            }
        }
    }];
}

// ----------------------------------------------------
// MARK: - 新增模块: 数据打包与上传 (Data Batching & Uploading)
// ----------------------------------------------------
- (void)addLocationToBatch:(CLLocation *)location
{
    if ([XDXShareInstance shareInstance].userId.integerValue>0) {
        // 将位置和当前状态打包成一个字典

        NSDictionary *dataPoint = @{
            @"id":@([NSString stringWithFormat:@"%@%@",[XDXShareInstance shareInstance].userId,[XDXTimeTool getNowTimeTimestamp]].integerValue),
            @"userId": [XDXShareInstance shareInstance].userId,
            @"latitude":  @(location.coordinate.latitude),
            @"longitude": @(location.coordinate.longitude),
            @"altitude": @(location.altitude),
            @"speed": @(location.speed<0?0:((int)(location.speed*3.6))),
            @"unlock": [NSString stringWithFormat:@"%d",_unLock],
            @"activity": @(self.activityState),
            @"createTime": [[XDXTimeTool currentDate] substringToIndex:19],
            @"notifyLog": @"0",
            @"degree" : @(self.locationManager.heading.trueHeading),
        };
        
        [self.pointBatch addObject:dataPoint];
        if (self.pointBatch.count>=20 || ([XDXTimeTool getNowTimeTimestamp].integerValue-self.uploadTime>60)) {
            self.uploadTime = [XDXTimeTool getNowTimeTimestamp].integerValue;
            [self uploadBatchData];
        }
        
        _unLock = NO;

        // 驾驶检测
        [self detectDrivingSession];
    }
}

- (void)uploadBatchData
{
    // 1. 线程安全地获取当前数据快照
    NSArray *dataToUpload = nil;
    @synchronized(self.pointBatch) {
        if (self.pointBatch.count == 0) {
            NSLog(@"[Upload] 没有数据需要上传");
            return;
        }
        // 创建数据快照，避免上传过程中数据被修改
        dataToUpload = [self.pointBatch copy];
    }
    
    NSLog(@"[Upload] 开始上传 %lu 个数据点", (unsigned long)dataToUpload.count);
 
    NSMutableDictionary *param = [NSMutableDictionary dictionary];
    [param setValue:dataToUpload forKey:@"trajectoryPoints"];
    CryptoHTTPKit *manager = [[CryptoHTTPKit alloc] init];
    [manager encryptedPOST:@"/apps/trajectory/upload"
    parameters:param
    success:^(NSDictionary *responseObject) {
        if ([responseObject[@"code"] integerValue] == 200) {
            NSLog(@"[Upload] 上传成功，清理已上传的数据");
            
            // 4. 上传成功后，线程安全地清理已上传的数据
            @synchronized(self.pointBatch) {
                // 移除已上传的数据点（从开头开始移除，保持顺序）
                NSInteger uploadedCount = dataToUpload.count;
                if (self.pointBatch.count >= uploadedCount) {
                    NSRange rangeToRemove = NSMakeRange(0, uploadedCount);
                    [self.pointBatch removeObjectsInRange:rangeToRemove];
                    NSLog(@"[Upload] 已清理 %ld 个数据点，剩余 %lu 个", (long)uploadedCount, (unsigned long)self.pointBatch.count);
                } else {
                    // 异常情况：pointBatch 中的数据少于上传的数据
                    NSLog(@"[Upload] 警告：数据不一致，清空所有数据");
                    [self.pointBatch removeAllObjects];
                }
            }
        } else {
            NSLog(@"[Upload] 上传失败，服务器返回错误: %@", responseObject[@"msg"]);
        }
    }
    failure:^(NSError *aError) {
        
    }];
}
 
- (void)batteryLevelDidChange:(NSNotification *)notification
{
    UIDevice *device = [UIDevice currentDevice];
    float batteryLevel = device.batteryLevel*100;
    
    // 电量也传输socket
    CLLocationCoordinate2D loc = [WGS84TOGCJ02 transformFromWGSToGCJ:[[XDXLocationManager shareInstance].lastLocation coordinate]];
    NSDictionary *dict = @{@"type":@"location_update",@"location":@{@"latitude":[NSString stringWithFormat:@"%f",loc.latitude],@"longitude":[NSString stringWithFormat:@"%f",loc.longitude],@"activity":self.activityString,@"speed":[NSString stringWithFormat:@"%d",self.lastLocation.speed<0?0:(int)(self.lastLocation.speed*3.6)],@"nickName":[XDXShareInstance shareInstance].nickName,@"lastLog":self.lastlog,@"battery":[NSString stringWithFormat:@"%.0f",[UIDevice currentDevice].batteryLevel*100],@"isCharge":([UIDevice currentDevice].batteryState==UIDeviceBatteryStateCharging)?@"1":@"0",@"isLocationAuth":([self.locationManager authorizationStatus]==kCLAuthorizationStatusAuthorizedAlways?@(1):@(0))}};
    [[XDXSocket shareInstance] sendMessage:dict];
    if (self.XDXLocationManagerLocationBlock) {
        self.XDXLocationManagerLocationBlock(dict);
    }
    
    if (batteryLevel<=10 && ([[XDXTimeTool getNowTimeTimestamp] integerValue]-self.batteryTime>=1800) && _batteryUp) {
        self.batteryTime = [[XDXTimeTool getNowTimeTimestamp] integerValue];
        _batteryUp = NO;

        NSMutableDictionary *param = [NSMutableDictionary dictionary];
        CryptoHTTPKit *manager = [[CryptoHTTPKit alloc] init];
        [manager encryptedPOST:@"/apps/data/batterynotification"
        parameters:param
        success:^(NSDictionary *responseObject) {
            
        }
        failure:^(NSError *aError) {
            
        }];
    }else{
        _batteryUp = YES;
    }
    
}

- (double)distanceBetweenOrderByLatitudeA:(double)latitude1 latitudeB:(double)latitude2 longitudeA:(double)longitude1 longitudeB:(double)longitude2
{
    CLLocation *curLocation = [[CLLocation alloc] initWithLatitude:latitude1 longitude:longitude1];
    CLLocation *otherLocation = [[CLLocation alloc] initWithLatitude:latitude2 longitude:longitude2];
    double  distance = [curLocation distanceFromLocation:otherLocation]/1000;
    return  distance;
}

- (void)handleScreenUnlock:(NSNotification *)notification
{
    _unLock = YES;
}

- (NSInteger)activityState
{
    if ([self.activityString isEqualToString:@"静止"]) {
        return 1;
    }else if ([self.activityString isEqualToString:@"步行"] ){
        return 2;
    }else if ([self.activityString isEqualToString:@"骑行"] ){
        return 3;
    }else if ([self.activityString isEqualToString:@"驾车"] ){
        return 4;
    }else if ([self.activityString isEqualToString:@"sos"] ){
        return 0;
    }
    return 1;
}

// ----------------------------------------------------
// MARK: - 自定义围栏逻辑实现
// ----------------------------------------------------
#pragma mark - 围栏距离计算和状态检查
/**
 * 触发进入围栏事件
 */
- (void)triggerGeofenceEntry:(GeofenceInfo *)geofence {
    NSLog(@"[Geofence] 进入围栏: %@", geofence.fenceName);
    [[HCToast shareInstance] showToast:[NSString stringWithFormat:@"[Geofence] 进入围栏: %@", geofence.fenceName]];
        
    // 发送网络请求
    [self sendGeofenceNotificationWithGeofence:geofence status:@"true"];
    
    [self.regionLog addObject:@{@"time":[XDXTimeTool currentDate],@"event":[NSString stringWithFormat:@"进入围栏: %@",geofence.fenceName]}];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *documentsDirectory = paths.firstObject;
    NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"regionLog.plist"];
    [self.regionLog writeToFile:plistPath atomically:YES];
}

/**
 * 触发离开围栏事件
 */
- (void)triggerGeofenceExit:(GeofenceInfo *)geofence {
    NSLog(@"[Geofence] 离开围栏: %@", geofence.fenceName);
    [[HCToast shareInstance] showToast:[NSString stringWithFormat:@"[Geofence] 离开围栏: %@", geofence.fenceName]];
    
    // 发送网络请求
    [self sendGeofenceNotificationWithGeofence:geofence status:@"false"];
    [self.regionLog addObject:@{@"time":[XDXTimeTool currentDate],@"event":[NSString stringWithFormat:@"离开围栏: %@",geofence.fenceName]}];
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
    NSString *documentsDirectory = paths.firstObject;
    NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"regionLog.plist"];
    [self.regionLog writeToFile:plistPath atomically:YES];
}

/**
 * 发送围栏通知到服务器
 */
- (void)sendGeofenceNotificationWithGeofence:(GeofenceInfo *)geofence status:(NSString *)status {

    NSMutableDictionary *param = [NSMutableDictionary dictionary];
    [param setValue:geofence.fenceId forKey:@"locationId"];
    [param setValue:geofence.fenceName forKey:@"locationName"];
    [param setValue:status forKey:@"status"];
    CryptoHTTPKit *manager = [[CryptoHTTPKit alloc] init];
    [manager encryptedPOST:@"/apps/data/arriveorleavenotification"
    parameters:param
    success:^(NSDictionary *responseObject) {
        
    }
    failure:^(NSError *aError) {
        
    }];
}

// MARK: - CLRegion 事件回调，转发给融合协调器
- (void)locationManager:(CLLocationManager *)manager didEnterRegion:(CLRegion *)region
{
    if (self.geofenceCoordinator) {
        [self.geofenceCoordinator ingestRegion:region didEnter:YES];
    }
}

- (void)locationManager:(CLLocationManager *)manager didExitRegion:(CLRegion *)region
{
    if (self.geofenceCoordinator) {
        [self.geofenceCoordinator ingestRegion:region didEnter:NO];
    }
}

- (void)locationManager:(CLLocationManager *)manager didDetermineState:(CLRegionState)state forRegion:(CLRegion *)region
{
    if (!self.geofenceCoordinator) return;
    if (state == CLRegionStateInside) {
        [self.geofenceCoordinator ingestRegion:region didEnter:YES];
    } else if (state == CLRegionStateOutside) {
        [self.geofenceCoordinator ingestRegion:region didEnter:NO];
    } else {
        // Unknown -> 不触发
    }
}

// ----------------------------------------------------
// MARK: - 驾驶检测与统计模块
// ----------------------------------------------------

/**
 * 检测驾驶会话
 */
- (void)detectDrivingSession
{
    [self.drivingTimer invalidate];
    self.drivingTimer = nil;
    self.drivingTimer = [NSTimer scheduledTimerWithTimeInterval:300 repeats:NO block:^(NSTimer * _Nonnull timer) {
        [self.drivingTimer invalidate];
        self.drivingTimer = nil;
        [[HomeViewController new] getMemberInfoWithUserId:[XDXShareInstance shareInstance].userId Date:[[XDXTimeTool currentDate] substringToIndex:10] Success:^(NSArray *data) {
            [self readMoreDataWithData:data IsLoopCheck:NO];
        } Error:^(NSDictionary *data) {

        }];
    }];
    [[NSRunLoop currentRunLoop] addTimer:self.drivingTimer forMode:NSDefaultRunLoopMode];
}

#pragma mark - 轨迹数据处理

- (void)readMoreDataWithData:(NSArray *)data
                 IsLoopCheck:(BOOL)isLoopCheck // 是否为driverlooptimer轮训时
{
    NSMutableArray *array = [NSMutableArray array];
    NSMutableDictionary *tempDic;
    for (NSDictionary *dict in data) {
        NSMutableDictionary *dic = [NSMutableDictionary dictionaryWithDictionary:dict];
        [dic setValue:dict[@"createTime"] forKey:@"create_time"];
        [dic setValue:dict[@"longitude"] forKey:@"longtitude"];
        if ([dict[@"activity"] integerValue]==0 || [dict[@"activity"] integerValue]==1) {
            [dic setValue:@"静止" forKey:@"activity"];
        }else if ([dict[@"activity"] integerValue]==4){
            [dic setValue:@"驾车" forKey:@"activity"];
        }else{
            [dic setValue:@"行程" forKey:@"activity"];
        }
        
        if (tempDic) {
            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
            [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
            dateFormatter.locale = [NSLocale systemLocale];
            dateFormatter.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierISO8601];
            
            NSDate *tempDate = [dateFormatter dateFromString:[tempDic[@"create_time"] substringToIndex:19]];
            NSInteger tempSecond = [tempDate timeIntervalSince1970];
            
            NSDate *dicDate = [dateFormatter dateFromString:[dic[@"create_time"] substringToIndex:19]];
            NSInteger dicSecond = [dicDate timeIntervalSince1970];
            if ((dicSecond-tempSecond)>600) {
                NSMutableDictionary *aaDic = [NSMutableDictionary dictionary];
                [aaDic setValue:[XDXTimeTool getNowTimeTimestamp] forKey:@"id"];
                [aaDic setValue:@"0" forKey:@"unlock"];
                [aaDic setValue:@"0" forKey:@"notify_log"];
                [aaDic setValue:tempDic[@"latitude"] forKey:@"latitude"];
                [aaDic setValue:tempDic[@"longtitude"] forKey:@"longtitude"];
                [aaDic setValue:tempDic[@"create_time"] forKey:@"create_time"];
                [aaDic setValue:@"静止" forKey:@"activity"];
                [aaDic setValue:@"0" forKey:@"speed"];
                [array addObject:aaDic];
                
                NSMutableDictionary *aDic = [NSMutableDictionary dictionary];
                [aDic setValue:[XDXTimeTool getNowTimeTimestamp] forKey:@"id"];
                [aDic setValue:@"0" forKey:@"unlock"];
                [aDic setValue:@"0" forKey:@"notify_log"];
                [aDic setValue:tempDic[@"latitude"] forKey:@"latitude"];
                [aDic setValue:tempDic[@"longtitude"] forKey:@"longtitude"];
                [aDic setValue:dic[@"create_time"] forKey:@"create_time"];
                [aDic setValue:@"静止" forKey:@"activity"];
                [aDic setValue:@"0" forKey:@"speed"];
                [array addObject:aDic];
            }
        }
        tempDic = [NSMutableDictionary dictionaryWithDictionary:dic];
        [array addObject:dic];
    }
    if (array.count>0) {
        if (![array.firstObject[@"create_time"] containsString:@"00:00"]) {
            if (![array.firstObject[@"activity"] isEqualToString:@"静止"]) {
                if ([[array.firstObject[@"create_time"] substringWithRange:NSMakeRange(11, 2)] integerValue]>1) {
                    {
                        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                        [dic setValue:[XDXTimeTool getNowTimeTimestamp] forKey:@"id"];
                        [dic setValue:@"0" forKey:@"unlock"];
                        [dic setValue:@"0" forKey:@"notify_log"];
                        [dic setValue:array.firstObject[@"latitude"] forKey:@"latitude"];
                        [dic setValue:array.firstObject[@"longtitude"] forKey:@"longtitude"];
                        [dic setValue:array.firstObject[@"create_time"] forKey:@"create_time"];
                        [dic setValue:@"静止" forKey:@"activity"];
                        [dic setValue:@"静止" forKey:@"org_activity"];
                        [dic setValue:@"0" forKey:@"speed"];
                        [array insertObject:dic atIndex:0];
                    }
                    {
                        NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                        [dic setValue:[XDXTimeTool getNowTimeTimestamp] forKey:@"id"];
                        [dic setValue:@"0" forKey:@"unlock"];
                        [dic setValue:@"0" forKey:@"notify_log"];
                        [dic setValue:array.firstObject[@"latitude"] forKey:@"latitude"];
                        [dic setValue:array.firstObject[@"longtitude"] forKey:@"longtitude"];
                        [dic setValue:[array.firstObject[@"create_time"] stringByReplacingCharactersInRange:NSMakeRange(11, 8) withString:@"00:00:00"] forKey:@"create_time"];
                        [dic setValue:@"静止" forKey:@"activity"];
                        [dic setValue:@"静止" forKey:@"org_activity"];
                        [dic setValue:@"0" forKey:@"speed"];
                        [array insertObject:dic atIndex:0];
                    }
                }else{
                    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                    [dic setValue:[XDXTimeTool getNowTimeTimestamp] forKey:@"id"];
                    [dic setValue:@"0" forKey:@"unlock"];
                    [dic setValue:@"0" forKey:@"notify_log"];
                    [dic setValue:array.firstObject[@"latitude"] forKey:@"latitude"];
                    [dic setValue:array.firstObject[@"longtitude"] forKey:@"longtitude"];
                    [dic setValue:[array.firstObject[@"create_time"] stringByReplacingCharactersInRange:NSMakeRange(11, 8) withString:@"00:00:00"] forKey:@"create_time"];
                    [dic setValue:array.firstObject[@"speed"] forKey:@"speed"];
                    [dic setValue:@"行程" forKey:@"activity"];
                    [dic setValue:dic[@"activity"] forKey:@"org_activity"];
                    [array insertObject:dic atIndex:0];
                }
            }else{
                NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                [dic setValue:[XDXTimeTool getNowTimeTimestamp] forKey:@"id"];
                [dic setValue:@"0" forKey:@"unlock"];
                [dic setValue:@"0" forKey:@"notify_log"];
                [dic setValue:array.firstObject[@"latitude"] forKey:@"latitude"];
                [dic setValue:array.firstObject[@"longtitude"] forKey:@"longtitude"];
                [dic setValue:[array.firstObject[@"create_time"] stringByReplacingCharactersInRange:NSMakeRange(11, 8) withString:@"00:00:00"] forKey:@"create_time"];
                [dic setValue:@"静止" forKey:@"activity"];
                [dic setValue:dic[@"activity"] forKey:@"org_activity"];
                [dic setValue:@"0" forKey:@"speed"];
                [array insertObject:dic atIndex:0];
            }
        }

            
        NSMutableArray *tempArray = [TrackTool segmentsFromLocationArray:array];
        tempArray = [TrackTool sortFormartArray:tempArray];
        tempArray = [TrackTool moveActivityToDriveWithArray:tempArray];
        NSMutableArray *activityArray = tempArray;
        if (activityArray.count>0) {
            NSMutableDictionary *dateDic = [NSMutableDictionary dictionary];
            [dateDic setValue:array.firstObject[@"create_time"] forKey:@"date"];
            [dateDic setValue:@(array.count) forKey:@"count"];
            [dateDic setValue:@(1) forKey:@"isShow"];
            NSMutableArray *dateArray = [NSMutableArray array];
            for (int j = 0; j < activityArray.count; j ++) {
                if (isLoopCheck==NO || (isLoopCheck && j<(activityArray.count-1))) {
                    NSMutableArray *array = activityArray[j];
                    if (array.count>1) {
                        if ([array.firstObject[@"activity"] isEqualToString:@"行程"] || [array.firstObject[@"activity"] isEqualToString:@"驾车"]) {
                            if (j>0) {
                                NSMutableDictionary *foDic = [activityArray[j-1] lastObject];
                                [foDic setValue:array.firstObject[@"activity"] forKey:@"activity"];
                                [array insertObject:foDic atIndex:0];
                            }
                        }
                        NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                        [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
                        dateFormatter.locale = [NSLocale systemLocale];
                        dateFormatter.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierISO8601];
                        NSDate *firstDate = [dateFormatter dateFromString:[array.firstObject[@"create_time"] substringToIndex:19]];
                        NSInteger firstSecond = [firstDate timeIntervalSince1970]+60;
                        
                        NSDate *lastDate = [dateFormatter dateFromString:[array.lastObject[@"create_time"] substringToIndex:19]];
                        NSInteger lastSecond = [lastDate timeIntervalSince1970];
                                                        
                        firstDate = [NSDate dateWithTimeIntervalSince1970:firstSecond];
                        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
                        [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
                        NSString *firstStr = [formatter stringFromDate:firstDate];
                        NSString *lastStr = [formatter stringFromDate:lastDate];
                        
                        NSString *time = [NSString stringWithFormat:@"%@",[firstStr substringWithRange:NSMakeRange(11, 5)]];
                        NSString *endTime = [NSString stringWithFormat:@"%@",[lastStr substringWithRange:NSMakeRange(11, 5)]];
                        NSString *timeRun = [NSString stringWithFormat:@"%@ - %@",time,endTime];
                        NSInteger second = lastSecond-firstSecond;
                        if (second/3600.0>1) {
                            timeRun = [timeRun stringByAppendingFormat:@"（%ld小时%ld分钟）",(long)(second/3600),(long)(second%3600/60)];
                        }else{
                            timeRun = [timeRun stringByAppendingFormat:@"（%@分钟）",[NSString stringWithFormat:@"%ld",(long)(second/60)]];
                        }
                        if ([array.firstObject[@"activity"] isEqualToString:@"驾车"]) {
                            
                            double distance = 0;
                            for (int i = 1; i < array.count; i++) {
                                distance = distance+[TrackTool distanceBetweenOrderByLatitudeA:[array[i-1][@"latitude"] doubleValue] latitudeB:[array[i][@"latitude"] doubleValue] longitudeA:[array[i-1][@"longtitude"] doubleValue] longitudeB:[array[i][@"longtitude"] doubleValue]];
                            }
                            NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                            [dic setValue:array forKey:@"array"];
                            [dic setValue:time forKey:@"time"];
                            [dic setValue:timeRun forKey:@"timeRun"];
                            if ([array.firstObject[@"activity"] isEqualToString:@"驾车"]){
                                CGFloat speed = 0;
                                for (NSDictionary *dict in array) {
                                    if (speed<=[dict[@"speed"] floatValue]) {
                                        speed = [dict[@"speed"] floatValue];
                                    }
                                }
                                [dic setValue:[NSString stringWithFormat:@"%.0f",speed] forKey:@"maxSpeed"];
                                [dic setValue:[NSString stringWithFormat:@"驾车 %.1f 公里",distance] forKey:@"title"];
                                
                                NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
                                [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
                                dateFormatter.locale = [NSLocale systemLocale];
                                dateFormatter.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierISO8601];
                                NSDate *startDate = [dateFormatter dateFromString:array.firstObject[@"create_time"]];
                                NSInteger startime = [startDate timeIntervalSince1970];
                                
                                BOOL isSend = NO;
                                for (NSDictionary *log in self.driveLog) {
                                    if ([log[@"tag"] integerValue]==[NSString stringWithFormat:@"%@%ld",[XDXShareInstance shareInstance].userId,(long)startime].integerValue) {
                                        isSend = YES;
                                    }
                                }
                                if (isSend==NO && distance>=1.0) {
                                    [self completeDrivingSessionWithDistance:distance MaxSpeed:speed StartTime:startime];
                                }
                            }
                            [dateArray insertObject:dic atIndex:0];
                        }
                    }
                    [dateDic setValue:dateArray forKey:@"array"];
                }
            }
        }
    }
}

/**
 * 完成驾驶会话
 */
- (void)completeDrivingSessionWithDistance:(double)distance
                                  MaxSpeed:(CGFloat)maxSpeed
                                StartTime:(NSInteger)startTime
{
    NSDictionary *param = [NSMutableDictionary dictionary];
    [param setValue:[NSString stringWithFormat:@"%d",(int)distance] forKey:@"distance"];
    [param setValue:[NSString stringWithFormat:@"%d",(int)maxSpeed] forKey:@"maxSpeed"];
    [param setValue:[NSString stringWithFormat:@"%@%ld",[XDXShareInstance shareInstance].userId,(long)startTime] forKey:@"tag"];
    CryptoHTTPKit *manager = [[CryptoHTTPKit alloc] init];
    [manager encryptedPOST:@"/apps/data/safedrivenotification"
    parameters:param
    success:^(NSDictionary *responseObject) {
        if ([responseObject[@"code"] integerValue]==200 && ![responseObject[@"msg"] isEqualToString:@"通知已发送过"]) {
            NSDictionary *log = [NSMutableDictionary dictionary];
            [log setValue:[NSString stringWithFormat:@"%d",(int)distance] forKey:@"distance"];
            [log setValue:[NSString stringWithFormat:@"%d",(int)maxSpeed] forKey:@"maxSpeed"];
            NSDate *timeData = [NSDate dateWithTimeIntervalSince1970:startTime];
            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
            [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
            dateFormatter.locale = [NSLocale systemLocale];
            dateFormatter.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierISO8601];
            NSString *time = [dateFormatter stringFromDate:timeData];
            [log setValue:time forKey:@"time"];
            [log setValue:[NSString stringWithFormat:@"%ld%@",(long)startTime,[XDXShareInstance shareInstance].userId] forKey:@"tag"];
            [self.driveLog addObject:log];

            NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
            NSString *documentsDirectory = paths.firstObject;
            NSString *plistPath = [documentsDirectory stringByAppendingPathComponent:@"driveLog.plist"];
            [self.driveLog writeToFile:plistPath atomically:YES];

        }
    }
    failure:^(NSError *aError) {
        
    }];
}


@end
